using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace DocumentCreationSystem.Views
{
    /// <summary>
    /// RWKV 模型管理窗口
    /// </summary>
    public partial class RWKVModelManagerWindow : Window
    {
        private readonly ILogger<RWKVModelManagerWindow> _logger;
        private readonly Services.RWKVManifestService _manifestService;
        private readonly Services.RWKVModelDownloadService _downloadService;
        private CancellationTokenSource? _cts;
        private readonly List<RowVM> _allRows = new();

        private class RowVM
        {
            public Services.RWKVModelItem Item { get; set; } = new();
            public string name => Item.name;
            public string TagsJoined => Item.tags == null ? string.Empty : string.Join(",", Item.tags);
            public long SizeMB => Item.size > 0 ? Item.size / (1024 * 1024) : 0;
            public bool IsLocal { get; set; }
            public string? FullPath { get; set; }
            public string Category { get; set; } = "清单";
        }

        public RWKVModelManagerWindow()
        {
            InitializeComponent();
            var sp = App.ServiceProvider;
            _logger = sp.GetRequiredService<ILogger<RWKVModelManagerWindow>>();
            _manifestService = sp.GetRequiredService<Services.RWKVManifestService>();
            _downloadService = sp.GetRequiredService<Services.RWKVModelDownloadService>();

            // 默认模型目录
            ModelDirTextBox.Text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".rwkv", "models");
            // 选择预设时自动填充到输入框（保留可追加多个地址的能力）
            if (FindName("ManifestPresetComboBox") is ComboBox preset && FindName("ManifestUrlTextBox") is TextBox urlBox)
            {
                preset.SelectionChanged += (s, e2) =>
                {
                    if (preset.SelectedItem is ComboBoxItem it && it.Content is string u && !string.IsNullOrWhiteSpace(u))
                    {
                        // 若输入框为空则直接填充；若已有内容则在末尾以分号追加
                        if (string.IsNullOrWhiteSpace(urlBox.Text)) urlBox.Text = u;
                        else if (!urlBox.Text.Contains(u, StringComparison.OrdinalIgnoreCase)) urlBox.Text += ";" + u;
                    }
                };
            }

            // 初始化标签筛选（默认“全部”）
            if (FindName("TagFilterComboBox") is ComboBox tagBox)
            {
                tagBox.ItemsSource = new List<string> { "全部" };
                tagBox.SelectedIndex = 0;
            }
        }

        private async void FetchManifest_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                StatusText.Text = "正在拉取清单...";
                var urls = ManifestUrlTextBox.Text;

                // 若选择镜像源，则替换 downloadUrl 中的 huggingface.co 为镜像域
                Func<IEnumerable<Services.RWKVModelItem>, IEnumerable<Services.RWKVModelItem>> applyMirror = list => list;
                if (FindName("MirrorComboBox") is ComboBox mirror && mirror.SelectedIndex == 1)
                {
                    applyMirror = list => list.Select(m => new Services.RWKVModelItem
                    {
                        name = m.name,
                        size = m.size,
                        SHA256 = m.SHA256,
                        downloadUrl = string.IsNullOrWhiteSpace(m.downloadUrl) ? m.downloadUrl : m.downloadUrl.Replace("huggingface.co", "hf-mirror.com"),
                        tags = m.tags,
                        category = m.category
                    });
                }

                var list = await _manifestService.FetchModelsAsync(urls);
                list = applyMirror(list).ToList();

                // 构建 _allRows 并更新标签与类别
                _allRows.Clear();
                foreach (var m in list)
                {
                    _allRows.Add(new RowVM { Item = m, Category = string.IsNullOrWhiteSpace(m.category) ? "清单" : m.category });
                }
                // 标签源
                var tags = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
                foreach (var r in _allRows)
                {
                    if (r.Item.tags != null)
                        foreach (var t in r.Item.tags)
                            if (!string.IsNullOrWhiteSpace(t)) tags.Add(t);
                }
                if (FindName("TagFilterComboBox") is ComboBox tagBox)
                {
                    var src = new List<string> { "全部" };
                    src.AddRange(tags);
                    tagBox.ItemsSource = src;
                    tagBox.SelectedIndex = 0;
                }
                UpdateCategoryFilter();
                RefreshGrid();
                StatusText.Text = $"已加载 {_allRows.Count} 个模型";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "拉取清单失败");
                StatusText.Text = "清单拉取失败";
            }
        }

        private void RefreshGrid()
        {
            var keyword = (FindName("SearchTextBox") as TextBox)?.Text?.Trim() ?? string.Empty;
            var tagSel = (FindName("TagFilterComboBox") as ComboBox)?.SelectedItem as string;
            var catSel = (FindName("CategoryFilterComboBox") as ComboBox)?.SelectedItem as string;
            IEnumerable<RowVM> q = _allRows;
            if (!string.IsNullOrEmpty(keyword))
            {
                q = q.Where(r => r.name.Contains(keyword, StringComparison.OrdinalIgnoreCase) || (r.TagsJoined?.Contains(keyword, StringComparison.OrdinalIgnoreCase) ?? false));
            }
            if (!string.IsNullOrEmpty(tagSel) && tagSel != "全部")
            {
                q = q.Where(r => (r.Item.tags?.Any(t => string.Equals(t, tagSel, StringComparison.OrdinalIgnoreCase)) ?? false));
            }
            if (!string.IsNullOrEmpty(catSel) && catSel != "全部")
            {
                q = q.Where(r => string.Equals(r.Category, catSel, StringComparison.OrdinalIgnoreCase));
            }
            ModelsGrid.ItemsSource = q.ToList();
        }

        private void UpdateCategoryFilter()
        {
            if (FindName("CategoryFilterComboBox") is ComboBox catBox)
            {
                var cats = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
                foreach (var r in _allRows)
                {
                    if (!string.IsNullOrWhiteSpace(r.Category)) cats.Add(r.Category);
                }
                var src = new List<string> { "全部" };
                src.AddRange(cats);
                catBox.ItemsSource = src;
                if (catBox.SelectedIndex < 0) catBox.SelectedIndex = 0;
            }
        }

        private void CategoryFilterComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            RefreshGrid();
        }

        private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            RefreshGrid();
        }

        private void TagFilterComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            RefreshGrid();
        }

        private async void ApplyAsCurrent_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (ModelsGrid.SelectedItem is not RowVM row) return;
                var cfgService = App.ServiceProvider.GetRequiredService<DocumentCreationSystem.Models.IAIModelConfigService>();
                var cfg = await cfgService.GetConfigAsync();
                cfg.Platform = "RWKV";
                cfg.RWKVConfig.SelectedModel = row.Item.name;
                await cfgService.SaveConfigAsync(cfg);
                StatusText.Text = "已设为当前模型（RWKV）";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "设为当前模型失败");
                StatusText.Text = "设为当前模型失败";
            }
        }








        private void BrowseModelDir_Click(object sender, RoutedEventArgs e)
        {
            var dlg = new System.Windows.Forms.FolderBrowserDialog();
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                ModelDirTextBox.Text = dlg.SelectedPath;
            }
        }

        private void ScanLocalModels_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var dir = ModelDirTextBox.Text.Trim();
                if (string.IsNullOrWhiteSpace(dir) || !Directory.Exists(dir))
                {
                    StatusText.Text = "本地模型目录不存在";
                    return;
                }
                var exts = new[] { ".pth", ".pt", ".bin", ".onnx", ".safetensors" };
                var files = Directory.EnumerateFiles(dir, "*.*", SearchOption.AllDirectories)
                                      .Where(f => exts.Contains(Path.GetExtension(f), StringComparer.OrdinalIgnoreCase))
                                      .Take(2000) // 安全上限
                                      .ToList();
                var rows = files.Select(f => new RowVM
                {
                    Item = new Services.RWKVModelItem
                    {
                        name = Path.GetFileName(f),
                        size = new System.IO.FileInfo(f).Length,
                        downloadUrl = string.Empty,
                        tags = new List<string> { "local" },
                        category = "本地"
                    },
                    IsLocal = true,
                    FullPath = f,
                    Category = "本地"
                });
                // 合并到 _allRows（同名去重：优先本地）
                var dict = _allRows.ToDictionary(r => (r.IsLocal ? (r.FullPath ?? r.name) : r.name), StringComparer.OrdinalIgnoreCase);
                foreach (var r in rows)
                {
                    dict[(r.FullPath ?? r.name)!] = r;
                }
                _allRows.Clear();
                _allRows.AddRange(dict.Values);
                // 更新标签
                if (FindName("TagFilterComboBox") is ComboBox tagBox)
                {
                    var tags = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
                    foreach (var r in _allRows)
                        if (r.Item.tags != null)
                            foreach (var t in r.Item.tags)
                                if (!string.IsNullOrWhiteSpace(t)) tags.Add(t);
                    var src = new List<string> { "全部" };
                    src.AddRange(tags);
                    tagBox.ItemsSource = src;
                    tagBox.SelectedIndex = 0;
                }
                RefreshGrid();
                StatusText.Text = $"已扫描本地模型 {files.Count} 个";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "扫描本地模型失败");
                StatusText.Text = "扫描本地模型异常";
            }
        }

        private void OpenModelFolder_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (ModelsGrid.SelectedItem is not RowVM row) return;
                string? path = row.FullPath;
                if (string.IsNullOrWhiteSpace(path))
                {
                    var dir = ModelDirTextBox.Text.Trim();
                    path = Path.Combine(dir, row.name);
                    if (!File.Exists(path))
                    {
                        // 尝试去掉模型名中的存档后缀以定位目录
                        path = Path.Combine(dir, Path.GetFileNameWithoutExtension(row.name));
                    }
                }
                string folder = File.Exists(path) ? Path.GetDirectoryName(path)! : path;
                if (!Directory.Exists(folder))
                {
                    StatusText.Text = "模型文件夹不存在";
                    return;
                }
                System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
                {
                    FileName = folder,
                    UseShellExecute = true,
                    Verb = "open"
                });
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "打开模型文件夹失败");
                StatusText.Text = "打开文件夹失败";
            }
        }

        private async void LoadLocalModel_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (ModelsGrid.SelectedItem is not RowVM row) return;
                // 优先使用 FullPath；否则去模型目录拼接名称
                string path = row.FullPath ?? Path.Combine(ModelDirTextBox.Text.Trim(), row.name);
                if (!File.Exists(path))
                {
                    StatusText.Text = "本地模型文件不存在";
                    return;
                }

                // 尝试在同目录自动探测 tokenizer 文件
                string? tok = null;
                try
                {
                    var dir = System.IO.Path.GetDirectoryName(path)!;
                    var cands = new[] { "tokenizer.json", "20B_tokenizer.json", "rwkv_tokenizer.json" };
                    tok = cands.Select(f => System.IO.Path.Combine(dir, f)).FirstOrDefault(File.Exists);
                }
                catch { }

                // 写入配置并切换为 RWKV（本地模式，默认 Onnx 后端）
                var cfgSvc = App.ServiceProvider.GetRequiredService<DocumentCreationSystem.Models.IAIModelConfigService>();
                var cfg = await cfgSvc.GetConfigAsync();
                cfg.Platform = "RWKV";
                cfg.RWKVConfig.SelectedModel = row.name;
                cfg.RWKVConfig.LocalModeEnabled = true;
                cfg.RWKVConfig.LocalModelPath = row.FullPath ?? Path.Combine(ModelDirTextBox.Text.Trim(), row.name);
                cfg.RWKVConfig.LocalBackendType = string.IsNullOrWhiteSpace(cfg.RWKVConfig.LocalBackendType) ? "onnx" : cfg.RWKVConfig.LocalBackendType;
                if (!string.IsNullOrWhiteSpace(tok)) cfg.RWKVConfig.LocalTokenizerPath = tok;
                await cfgSvc.SaveConfigAsync(cfg);

                // 通知 AI 服务重载，使本地后端生效
                if (App.ServiceProvider.GetService<DocumentCreationSystem.Services.IAIService>() is DocumentCreationSystem.Services.AIServiceManager aiMgr)
                {
                    await aiMgr.ReloadConfigurationAsync();
                }

                StatusText.Text = tok == null
                    ? "已启用本地模式（ONNX）。未找到 tokenizer，稍后可在设置中补充。"
                    : $"已启用本地模式（ONNX），已发现 tokenizer: {System.IO.Path.GetFileName(tok)}";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "加载本地模型失败");
                StatusText.Text = "加载本地模型异常";
            }
        }



        private async void DownloadModel_Click(object sender, RoutedEventArgs e)
        {
            if (ModelsGrid.SelectedItem is not RowVM row) return;
            var item = row.Item;

            try
            {
                Directory.CreateDirectory(ModelDirTextBox.Text);
                var dest = Path.Combine(ModelDirTextBox.Text, item.name);

                _cts?.Cancel();
                _cts = new CancellationTokenSource();

                StatusText.Text = "开始下载...";
                ProgressBar.IsIndeterminate = true;

                var progress = new Progress<Services.RWKVDownloadProgress>(p =>
                {
                    if (p.Total > 0)
                    {
                        ProgressBar.IsIndeterminate = false;
                        ProgressBar.Value = p.Percent;
                    }
                    else
                    {
                        ProgressBar.IsIndeterminate = true;
                    }
                    StatusText.Text = $"{p.Status} {(p.Total > 0 ? $"{p.Percent:F1}%" : string.Empty)}";
                });

                var ok = await _downloadService.DownloadAsync(
                    item.downloadUrl,
                    dest,
                    progress,
                    item.SHA256,
                    _cts.Token);

                if (ok)
                {
                    StatusText.Text = "下载完成并已校验";
                }
                else
                {
                    StatusText.Text = "下载失败或已取消";
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "下载失败");
                StatusText.Text = "下载异常";
            }
        }

        private void Close_Click(object sender, RoutedEventArgs e)
        {
            _cts?.Cancel();
            Close();
        }

        private async void ConvertToOnnx_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (ModelsGrid.SelectedItem is not RowVM row) return;
                var svc = App.ServiceProvider.GetRequiredService<DocumentCreationSystem.Services.IModelConversionService>();
                string input = row.FullPath ?? Path.Combine(ModelDirTextBox.Text.Trim(), row.name);
                if (!File.Exists(input)) { StatusText.Text = "源文件不存在"; return; }
                var outPath = Path.ChangeExtension(input, ".onnx");
                // TODO: 让用户在设置中配置 Python 与脚本路径，这里暂用占位路径
                string python = "python";
                string script = "rwkv_export_to_onnx.py"; // 由用户提供
                StatusText.Text = "开始转换为 ONNX...";
                var ok = await svc.ConvertToOnnxAsync(input, outPath, python, script);
                StatusText.Text = ok ? $"已生成: {outPath}" : "转换失败";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "转换 ONNX 失败");
                StatusText.Text = "转换 ONNX 异常";
            }
        }

        private async void ConvertToGguf_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (ModelsGrid.SelectedItem is not RowVM row) return;
                var svc = App.ServiceProvider.GetRequiredService<DocumentCreationSystem.Services.IModelConversionService>();
                string input = row.FullPath ?? Path.Combine(ModelDirTextBox.Text.Trim(), row.name);
                if (!File.Exists(input)) { StatusText.Text = "源文件不存在"; return; }
                var outPath = Path.ChangeExtension(input, ".gguf");
                string python = "python";
                string script = "rwkv_export_to_gguf.py"; // 由用户提供
                StatusText.Text = "开始转换为 GGUF...";
                var ok = await svc.ConvertToCppFormatAsync(input, outPath, python, script, "gguf");
                StatusText.Text = ok ? $"已生成: {outPath}" : "转换失败";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "转换 GGUF 失败");
                StatusText.Text = "转换 GGUF 异常";
            }
        }

    }
}

